package org.jvm.instruction.extended;

import org.jvm.instruction.base.*;
import org.jvm.instruction.loads.aload.ALOAD;
import org.jvm.instruction.loads.dload.DLOAD;
import org.jvm.instruction.loads.fload.FLOAD;
import org.jvm.instruction.loads.iload.ILOAD;
import org.jvm.instruction.loads.lload.LLOAD;
import org.jvm.instruction.math.IINC;
import org.jvm.instruction.stores.astore.ASTORE;
import org.jvm.instruction.stores.dstore.DSTORE;
import org.jvm.instruction.stores.fstore.FSTORE;
import org.jvm.instruction.stores.istore.ISTORE;
import org.jvm.instruction.stores.lstore.LSTORE;
import org.jvm.rtda.thread.Frame;

import java.util.*;

/**
 * 拓展操作指令，将单字节操作数的指令拓展为双字节操作数
 *
 * @author 海燕
 * @date 2023/1/29
 */
public class WIDE implements Instruction {

    /**
     * 被拓展的指令
     */
    private Instruction modifiedInstruction;


    private final Map<Integer, Class> classMap;

    {
        this.classMap = new HashMap<>();
        this.classMap.put(0x15, ILOAD.class);
        this.classMap.put(0x16, LLOAD.class);
        this.classMap.put(0x17, FLOAD.class);
        this.classMap.put(0x18, DLOAD.class);
        this.classMap.put(0x19, ALOAD.class);
        this.classMap.put(0x36, ISTORE.class);
        this.classMap.put(0x37, LSTORE.class);
        this.classMap.put(0x38, FSTORE.class);
        this.classMap.put(0x39, DSTORE.class);
        this.classMap.put(0x3a, ASTORE.class);
        this.classMap.put(0x84, IINC.class);
    }


    @Override
    public void fetchOperands(ByteCodeReader reader) {
        /**
         * 先读1字节操作数，确定被拓展的指令
         */
        int opcode = reader.readUint8();
        Class instructionClass = classMap.get(opcode);
        if (instructionClass == null) {
            throw new RuntimeException("没有对应指令");
        }
        //根据对应的指令继续读取操作数初始化被拓展指令
        newInstruction(instructionClass, reader);
    }

    private void newInstruction(Class clazz, ByteCodeReader reader) {
        try {
            if (IINC.class.isAssignableFrom(clazz)) {
                IINC iinc = (IINC) clazz.newInstance();
                iinc.setIndex(reader.readUint16());
                iinc.setConstValue(reader.readInt16());
                this.modifiedInstruction = iinc;
            } else {
                Index8Instruction index8Instruction = (Index8Instruction) clazz.newInstance();
                index8Instruction.setIndex(reader.readUint16());
                this.modifiedInstruction = index8Instruction;
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 直接执行被拓展指令的执行方法
     *
     * @param frame
     */
    @Override
    public void execute(Frame frame) {
        this.modifiedInstruction.execute(frame);
    }
}
